package nl.sogyo.objectvisualisatie.GUI;

import java.awt.BorderLayout;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import nl.sogyo.objectvisualisatie.core.Model;
import nl.sogyo.objectvisualisatie.data.ObjectInfo;

import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.Field;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Method;


@SuppressWarnings("serial")
public class ObjectInfoView extends JPanel implements Observer, ListSelectionListener{

	private JList objectInfoList;	   
    private DefaultListModel objectInfoListModel;
    private Model model;
    	
	public ObjectInfoView()
	{
		super(new BorderLayout());
		objectInfoListModel = new DefaultListModel();
        objectInfoList = new JList(objectInfoListModel);//create a JList
        objectInfoList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        objectInfoList.setSelectedIndex(0);
        objectInfoList.addListSelectionListener(this);
        objectInfoList.setVisibleRowCount(10);
        //objectList.setSize(300, 500);
        JScrollPane objectListScrollPane = new JScrollPane(objectInfoList,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		add(objectListScrollPane, BorderLayout.CENTER);
		objectInfoListModel.addElement("No objectinfo available yet");
	}

	public void valueChanged(ListSelectionEvent e) {
		// TODO Auto-generated method stub
	}
	
	public void initalise(Model model) {
		this.model = model;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void update()
	{
		ObjectInfo info = null;
		objectInfoListModel.removeAllElements();
		for(ObjectInfo objectInfo: model.getobjectsList())
		{
			if(objectInfo.isSelected())
			{
				info = objectInfo;
				break;
			}
		}
		if(info != null)
		{	
			objectInfoListModel.addElement("------Object name------");
			objectInfoListModel.addElement(info.getClassName() +" ("+info.getId()+")");
			objectInfoListModel.addElement("----------Methods----------");
			int i = 0;			
			for(Method method : info.getMethods())
			{
				String name = method.name();
				if(i > 0 && method.name().equals("<init>"))break;
				if(method.name().equals("<init>")) name = info.getClassName()+"()";
				objectInfoListModel.addElement(	getAccesModifier(method) +
												getReturnType(method)+" "+
												name+" ("+
												getArguments(method)+")");
				i++;
			}
			objectInfoListModel.addElement("------------Fields-----------");
			HashMap<Field, Object> map = (HashMap<Field, Object>) info.getFields().clone();
	    	for(Entry<Field, Object> entry : map.entrySet())
	    	{
	    		String[] fieldType = entry.getKey().typeName().toString().split("\\."); 	//fieldname with package and class 
	    		String cleanType = fieldType[(fieldType.length-1)];//entry.getKey().typeName(); 				//fieldtype
	    		
	    		String[] fieldName = entry.getKey().toString().split("\\."); 	//fieldname with package and class 
				String cleanField = fieldName[(fieldName.length-1)]; 			// fieldname without package and class
	    		
				String fieldValue = ""; 										// value of a field
				if(entry.getValue() != null)fieldValue = entry.getValue().toString();
				objectInfoListModel.addElement(cleanType +" "+ cleanField +": "+ fieldValue);
			}
		}
	}
	
	private String getAccesModifier(Method method)
	{
		String accesmodifier = "";
		if(method.isAbstract()) 	accesmodifier += "abstract ";
		if(method.isFinal()) 		accesmodifier += "final ";
		if(method.isPrivate())		accesmodifier += "private ";
		if(method.isProtected())	accesmodifier += "protected ";
		if(method.isPublic()) 		accesmodifier += "public ";
		if(method.isStatic()) 		accesmodifier += "static ";
		if(method.isSynchronized()) accesmodifier += "synchronized ";
		return accesmodifier;
	}
	
	private String getReturnType(Method method)
	{
		String[] returnType = method.returnTypeName().toString().split("\\.");
		String cleanReturnType = returnType[(returnType.length-1)]; 
		if(method.isConstructor()) cleanReturnType = "";		
		return cleanReturnType;
	}
	
	private String getArguments(Method method)
	{
		String arguments = "";
		int i = 0;
		try {			
			for(LocalVariable local : method.arguments())
			{
				String[] argument = local.typeName().toString().split("\\.");
				String cleanArgument = argument[(argument.length-1)]; 		
				if(i > 0) arguments += ", ";
				arguments += cleanArgument +" "+local.name();	    		
	    		i++;
			}
		} catch (AbsentInformationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return arguments;
	}
}